/*
 * Copyright 2011 Kim Lindhardt Madsen
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package dk.lindhardt.gwt.geie.client.evaluate;

import org.matheclipse.parser.client.ast.FunctionNode;
import org.matheclipse.parser.client.ast.SymbolNode;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * User: AnAmuser
 * Date: 24-08-11
 * <p/>
 * Evaluate expressions to <code>boolean</code> values
 */
public class GeieDateEvaluator {

   static Map<String, Boolean> SYMBOL_DATE_MAP;
   static Map<String, Object> FUNCTION_DATE_MAP;

   public static double EPSILON = 1.0e-15;

   static void addFunction(String name, IFunction function) {
      function.setFunctionName(name);
      FUNCTION_DATE_MAP.put(name, function);
   }

   static {
      SYMBOL_DATE_MAP = new HashMap<String, Boolean>();

      FUNCTION_DATE_MAP = new HashMap<String, Object>();

      FUNCTION_DATE_MAP.put(
            "now", new IDate0Function() {
               public Date evaluate() {
                  return new Date();
               }
            });
      FUNCTION_DATE_MAP.put(
            "today", new IDate0Function() {
               public Date evaluate() {
                  Date date = new Date();
                  date.setHours(0);
                  date.setMinutes(0);
                  date.setSeconds(0);
                  return date;
               }
            });
      FUNCTION_DATE_MAP.put(
            "date", new IDateDouble3Function() {
               @Override
               Date evaluateDate(double arg1, double arg2, double arg3) {
                  return new Date((int) arg1 - 1900, (int) arg2 - 1, (int) arg3);
               }
            });

   }

   private GeieEvaluator geieEvaluator;

   /**
    * New boolean evaluator
    * @param geieEvaluator
    */
   public GeieDateEvaluator(GeieEvaluator geieEvaluator) {
      this.geieEvaluator = geieEvaluator;
   }

   Date evaluateFunction(final FunctionNode functionNode) {
      if (functionNode.size() > 0
            && functionNode.getNode(0) instanceof SymbolNode) {
         String symbol = functionNode.getNode(0).toString().toLowerCase();
         if (functionNode.size() == 1) {
            Object obj = FUNCTION_DATE_MAP.get(symbol);
            if (obj instanceof IDate0Function) {
               return ((IDate0Function) obj).evaluate();
            }
         } else if (functionNode.size() == 4) {
            Object obj = FUNCTION_DATE_MAP.get(symbol);
            if (obj instanceof IDate3Function) {
               return ((IDate3Function) obj).evaluate(
                     geieEvaluator.evaluateNode(functionNode.getNode(1)),
                     geieEvaluator.evaluateNode(functionNode.getNode(2)),
                     geieEvaluator.evaluateNode(functionNode.getNode(3)));
            }
         }
      }
      throw new ArithmeticException("Evaluating not possible for: " + functionNode.toString());

   }
}
